// Copyright (c) 2018 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.

#ifndef STORAGE_LEVELDB_UTIL_NO_DESTRUCTOR_H_
#define STORAGE_LEVELDB_UTIL_NO_DESTRUCTOR_H_

#include <type_traits>
#include <utility>

namespace leveldb {

// Wraps an instance whose destructor is never called.
//
// This is intended for use with function-level static variables.
template <typename InstanceType>
class NoDestructor {
public:
    template <typename... ConstructorArgTypes>
    explicit NoDestructor(ConstructorArgTypes&&... construct_args) {
        static_assert(sizeof(instance_storage_) >= sizeof(InstanceType),
                      "instance_storage_ is not large enough to hold the instance");
        static_assert(
            alignof(decltype(instance_storage_)) >= alignof(InstanceType),
            "instance_storage_ does not meet the instance's alignment requirement");
        /**
         * using placement new to construct an object of type InstanceType within the
         *  previously allocated storage area instance_storage_. This is a common 
         * technique used in C++ when you want to create an object at a specific
         *  memory location, such as when managing custom memory buffers or working 
         * with placement new. 
         */
        new (&instance_storage_)
            InstanceType(std::forward<ConstructorArgTypes>(construct_args)...);
    }

    ~NoDestructor() = default;

    NoDestructor(const NoDestructor&) = delete;
    NoDestructor& operator=(const NoDestructor&) = delete;

    InstanceType* get() {
        return reinterpret_cast<InstanceType*>(&instance_storage_);
    }

private:
    /**
     * the code is creating a storage area (instance_storage_) that 
     * is suitably aligned for an object of type InstanceType and has 
     * the same size as an InstanceType object. This is commonly used
     *  in situations where you want to manually manage the construction
     *  and destruction of objects with specific alignment requirements,
     *  such as when implementing custom memory allocation or managing 
     * memory buffers.
     * std::aligned_storage::type:the POD type of at least size Len with 
     * alignment requirement Align 
     * 
     * The typename keyword is used to indicate that the following
     *  expression std::aligned_storage<sizeof(InstanceType), 
     * alignof(InstanceType)>::type should be treated as a type. 
     * This is necessary because in C++, when you are dealing with 
     * dependent types (types that depend on template parameters), 
     * you often need to use typename to specify that a nested type or 
     * member is indeed a type.
     */
    typename std::aligned_storage<sizeof(InstanceType),
                                  alignof(InstanceType)>::type instance_storage_;
};

}  // namespace leveldb

#endif  // STORAGE_LEVELDB_UTIL_NO_DESTRUCTOR_H_
